using System;
using System.Collections.Generic;
using EPiServer.Core;
using TemplateFoundation.PageTypes;

namespace TemplateFoundation.PageTypeIcons.IconHandlers
{
    /// <summary>
    /// <para>Handler to match specific properties and display icons depending on state.</para>
    /// </summary>
    public class PropertyHandler : IconHandlerBase {

        #region Constructors
        /// <summary>
        /// <para>Initializes a new Handler that displays icons based on property values.</para>
        /// </summary>
        /// <param name="propertyName">The name of the EPiServer page property to check.</param>
        /// <param name="propertyValue">The value to match the property value against.</param>
        /// <param name="propertyEmpty">A value indicating whether to match against an empty property value.</param>
        /// <param name="imageUrl">The virtual path to the icon show.</param>
        /// <param name="toolTip">The tooltip for the icon.</param>
        /// <param name="excludedPageTypes">The types of pages not checked.</param>
        /// <param name="hideIfShortcut">A value indicating if the icon should be omitted of the LinkType of the page is set to point somewhere else.</param>
        public PropertyHandler(string propertyName, object propertyValue, bool propertyEmpty, string imageUrl, string toolTip, Type[] excludedPageTypes, bool hideIfShortcut) {
            
            IconToolTip = toolTip;
            IconUrl = imageUrl;
            PropertyEmpty = propertyEmpty;
            PropertyName = propertyName;
            PropertyValue = propertyValue;
            HideIfShortcut = hideIfShortcut;

            if (excludedPageTypes != null)
            {
                ExcludedPageTypes = excludedPageTypes;
            }
            else
            {
                ExcludedPageTypes = new Type[0];
            }
        }
        #endregion

        #region Properties

        /// <summary>
        /// A value indicating if the icon should be omitted of the LinkType of the page is set to point somewhere else.
        /// </summary>
        protected virtual bool HideIfShortcut {
            get;
            set;
        }

        /// <summary>
        /// <para>Gets the name of the EPiServer page property to check.</para>
        /// </summary>
        protected virtual string PropertyName {
            get;
            private set;
        }

        /// <summary>
        /// <para>Gets the value to match the property value against.</para>
        /// </summary>
        protected virtual object PropertyValue {
            get;
            private set;
        }

        /// <summary>
        /// <para>Gets a value indicating whether to match against an empty property value.</para>
        /// </summary>
        protected virtual bool PropertyEmpty {
            get;
            private set;
        }

        /// <summary>
        /// The types of pages not checked.
        /// </summary>
        protected virtual Type[] ExcludedPageTypes {
            get;
            private set;
        }

        #endregion

        #region Properties
        /// <summary>
        /// <para>Determines whether the specified page is match for the current tree icon handler and an icon should be returned.</para>
        /// </summary>
        /// <param name="page">The current page in the page tree to check for match against.</param>
        /// <returns>
        /// 	<c>true</c> if the specified page is match and an icon should be returned; otherwise, <c>false</c>.
        /// </returns>
        public override bool IsMatch(PageTypeBase page)
        {
            if (page == null)
            {
                return false;
            }

            if (page.ParentLink.ID.Equals(PageReference.WasteBasket.ID))
            {
                return false;
            }

            if (IsAssignableFrom(page.GetType(), ExcludedPageTypes))
            {
                return false;
            }

            if (HideIfShortcut && 
                (page.LinkType == PageShortcutType.External || 
                page.LinkType == PageShortcutType.FetchData || 
                page.LinkType == PageShortcutType.Shortcut)) {
                return false;
            }

            var property = page.Property[PropertyName];

            if (property.IsNull)
            {
                return PropertyEmpty;
            }

            if (PropertyValue != null)
            {
                // TODO: Perhaps make this a real type check instead of using ToString(). Using TypeConverter? Using PropertyData.ParseToSelf()?
                var valueOfProperty = page.Property[PropertyName];
                return PropertyValue.Equals(valueOfProperty.Value);
            }

            return PropertyEmpty ? false : true;
        }

        #endregion

        #region Private Helpers
        /// <summary>
        /// <para>Checks if a specified type is assignable from any of the types in the provided list.</para>
        /// </summary>
        /// <param name="thisType">The type to check.</param>
        /// <param name="listOfTypes">A list of types to check against.</param>
        private static bool IsAssignableFrom(Type thisType, IEnumerable<Type> listOfTypes) {
            foreach (var t in listOfTypes) {
                if (thisType.IsAssignableFrom(t) || t.IsAssignableFrom(thisType))
                    return true;
            }
            return false;
        }
        #endregion
    }
}